#include "ComponentFlyAroundBehavior.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentCreatureSounds.h"
#include "ComponentPathfinding.h"
#include "Subsystems/SubsystemTerrain.h"
#include "GameRandom.hpp"
#include "Engine/MathUtils.hpp"
#include "Log.h"

#include "GameSingleton.h"
#include "GameRegistry.hpp"
#include "GameThreadPool.hpp"

#include <iostream>

namespace PocketSurvival
{

    // ************** 【状态机】 **************

    ComponentFlyAroundBehavior::StateMachine::StateMachine(ComponentFlyAroundBehavior *flyAroundBehavior) : m_flyAround(flyAroundBehavior), EasyMachine(MachineState::Inactive) {}

    void ComponentFlyAroundBehavior::StateMachine::enter()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            break;
        case MachineState::Stuck:
            if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.5f)
            {
                // m_flyAround->componentCreature->componentCreatureSounds->playIdleSound(false);
                m_flyAround->m_importanceLevel = 1.0f;
            }
            break;
        case MachineState::Fly:
            m_flyAround->m_angle = GameSingleton::gameRandom->getFloat(0.0f, MathUtils::GetPI() * 2.0f);
            m_flyAround->componentPathfinding->stop();
            break;
        }
    }

    void ComponentFlyAroundBehavior::StateMachine::update(float dt)
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            MACHINE_DELEGATE()
            {
                if (m_flyAround->isActive())
                {
                    changeTo(MachineState::Fly);
                }
            }
            break;
        case MachineState::Stuck:
            MACHINE_DELEGATE()
            {
                changeTo(MachineState::Fly);
            }
            break;
        case MachineState::Fly:
            MACHINE_DELEGATE()
            {
                Vector3 position;
                m_flyAround->componentCreature->componentBody->getPosition(position);

                if (m_flyAround->componentPathfinding->destination == FastVector3::Zero)
                {
                    float num = (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.2f) ? GameSingleton::gameRandom->getFloat(0.4f, 0.6f) : (0.0f - GameSingleton::gameRandom->getFloat(0.4f, 0.6f));
                    m_flyAround->m_angle = MathUtils::NormalizeAngle(m_flyAround->m_angle + num);
                    Vector2 vector = Vector2::CreateFromAngle(m_flyAround->m_angle);
                    Vector3 value(position + (Vector3(vector.posX, 0.0f, vector.posY) * 10.0f));

                    float topHeight = m_flyAround->estimateHeight(Vector2(value.posX, value.posZ), 8);
                    value.posY = topHeight + GameSingleton::gameRandom->getFloat(3.0f, 5.0f);

                    m_flyAround->componentPathfinding->setDestination(value, GameSingleton::gameRandom->getFloat(0.6f, 1.05f), 6.0f, 0, false, true, false, nullptr);

                    // if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.15f)
                    // {
                    //     m_flyAround->componentCreature->componentCreatureSounds->playIdleSound(false);
                    // }
                }
                else if (m_flyAround->componentPathfinding->isStuck)
                {
                    changeTo(MachineState::Stuck);
                }
            }
            break;
        }
    }

    void ComponentFlyAroundBehavior::StateMachine::leave() {}

    // **************************************



    ComponentFlyAroundBehavior::~ComponentFlyAroundBehavior()
    {
        delete m_stateMachine;
    }

    float ComponentFlyAroundBehavior::getImportanceLevel()
    {
        return m_importanceLevel;
    }
    float ComponentFlyAroundBehavior::estimateHeight(const Vector2 &position, int32_t radius)
    {
        int32_t num = 0;
        for (int32_t index = 0; index < 15; index++)
        {
            int32_t x = Terrain::ToCell(position.posX) + GameSingleton::gameRandom->getInt(-radius, radius);
            int32_t z = Terrain::ToCell(position.posY) + GameSingleton::gameRandom->getInt(-radius, radius);
            num = MathUtils::Max<int32_t>(num, GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>()->getTopHeight(x, z));
        }
        return num;
    }

    void ComponentFlyAroundBehavior::update(float dt)
    {
        if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.05f * dt)
        {
            m_importanceLevel = GameSingleton::gameRandom->getFloat(1.0f, 2.0f);
        }
        if (isActive())
        {
            m_stateMachine->update(dt);
        }
        else if (m_stateMachine->currentState() !=  MachineState::Inactive)
        {
            m_stateMachine->changeTo(MachineState::Inactive);
        }
    }

    static const std::string componentName = "FlyAroundBehavior";
    const std::string &ComponentFlyAroundBehavior::getName() const
    {
        return componentName;
    }
    const std::string &ComponentFlyAroundBehavior::GetName()
    {
        return componentName;
    }
    void ComponentFlyAroundBehavior::load(const nlohmann::json &jsonData)
    {
        componentCreature    = GameSingleton::gameRegistry->get<ComponentCreature *>(entity);
        componentPathfinding = GameSingleton::gameRegistry->get<ComponentPathfinding *>(entity);

        m_stateMachine = new StateMachine(this);
    }

}
